package com.liu.consumer.config;

import com.alibaba.fastjson.JSON;
import com.liu.consumer.annotation.ConsumerClient;
import com.liu.consumer.message.PullMessage;
import com.liu.message.MessageTypeEnum;
import com.liu.message.impl.ResponseMessage;
import com.liu.util.HashFixedLength;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @param
 * @BelongsProject: QueueDemo2
 * @BelongsPackage: com.liu.consumer.mq
 * @author: L
 * @Date: 2023/10/21 15:39
 * @return
 */
@Configuration
@ConfigurationProperties(prefix = "consumer")
@Slf4j
public class ClientRegister implements SmartInitializingSingleton, ApplicationContextAware {
    @Setter
    private String ip;
    @Setter
    private Integer port;
    @Autowired
    private RestTemplate restTemplate;
    private ApplicationContext applicationContext;
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    @Override
    public void afterSingletonsInstantiated() {
        Map<String, Object> beans = this.applicationContext.getBeansWithAnnotation(ConsumerClient.class)
                .entrySet().stream().filter(entry -> !ScopedProxyUtils.isScopedTarget(entry.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        beans.forEach(this::registerClients);
    }

    private void registerClients(String beanName, Object bean) {
        Class<?> clazz = AopProxyUtils.ultimateTargetClass(bean);

        ConsumerClient annotation = clazz.getAnnotation(ConsumerClient.class);

        String topic;
        topic = StringUtils.hasText(annotation.value()) ? annotation.value() : annotation.topic();
        if (!StringUtils.hasText(topic)) {
            throw new RuntimeException("主题为空");
        }
        String cron = annotation.cron();
        int num = annotation.num();

        GenericApplicationContext genericApplicationContext = (GenericApplicationContext) applicationContext;

        Client client = (Client) genericApplicationContext.getBean(beanName);

        StringBuffer stringBuffer = new StringBuffer();
        String url = stringBuffer.append("http://").append(ip).append(":").append(port).toString();
        if (!client.isRunning()) {
            try {
                threadPoolTaskScheduler.schedule(new Runnable() {
                    @Override
                    public void run() {
                        client.setRunning(true);
                        log.info("执行中");
                        PullMessage message = new PullMessage(MessageTypeEnum.PULL_ORDINARY_REQUEST.getType(),
                                HashFixedLength.encode(topic),
                                num);
                        String jsonString = JSON.toJSONString(message);

                        // byte数组被解析了
                        ResponseMessage responseMessage = restTemplate.postForObject(url, jsonString, ResponseMessage.class);
                        if (responseMessage.getExceptionValue() != null) {
                            log.error(responseMessage.getExceptionValue().toString());
                            return;
                        }
                        if (responseMessage.getReturnValue() == null) {
                            return;
                        }
                        Object returnValue = responseMessage.getReturnValue();
                        List<LinkedHashMap<String, Object>> links = (List<LinkedHashMap<String, Object>>) returnValue;
                        if (links == null || links.isEmpty()) {
                            return;
                        }

                        // 在这里  因为我传输的是JSON串,并且使用的是restTemplate,所以我无法获取反序列化类型
                        // 如果有时间的话应该细看下restTemplate,看看能不能获取请求头
                        // 但是还好吧  就像现在的前后端分离项目,默认就是使用JSON...,并没有参数表名参数体的类型,完全可以约定好
                        client.handler(links);
                    }
                }, new CronTrigger(cron));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
